package main

import (
	"context"
	"encoding/json"
	"fmt"
	"gin_study_blog/core"
	"github.com/olivere/elastic/v7"
	"github.com/sirupsen/logrus"
)

var client *elastic.Client

// EsConnect es 封装
func EsConnect() *elastic.Client {
	var err error
	sniffOpt := elastic.SetSniff(false)

	host := "http://127.0.0.1:9200"

	c, err := elastic.NewClient(
		elastic.SetURL(host),
		sniffOpt,
		elastic.SetBasicAuth("", ""),
	)

	if err != nil {
		logrus.Errorf("es连接失败 %s", err.Error())
	}
	return c
}

func init() {
	// 读取配置文件
	core.YamlInitConfig()
	core.InitLogger()
	client = EsConnect()

}

type DemoModel struct {
	ID        string `json:"-"`
	Title     string `json:"title"`
	UserID    uint   `json:"user_id"`
	CreatedAt string `json:"created_at"`
}

func (DemoModel) Index() string {
	return "demo_index"
}

// Create 增加内容
func Create(data *DemoModel) (err error) {
	// BodyJson 就是将 data 转为 json
	indexResponse, err := client.Index().
		Index(data.Index()).
		BodyJson(data).Do(context.Background())
	if err != nil {
		logrus.Error(err.Error())
		return err
	}

	logrus.Infof("%#v", indexResponse)
	data.ID = indexResponse.Id
	return nil
}

// FindList 列表查询所有字段
func FindList(key string, page, limit int) (demoList []DemoModel, count int) {
	// 创建一个新的布尔查询
	boolSearch := elastic.NewBoolQuery()
	from := page
	if key != "" {
		// Must方法表示这个匹配查询是必需的，也就是说只有当这个匹配查询返回结果时，布尔查询才会返回结果。
		boolSearch.Must(
			// NewMatchQuery 必须完全匹配 NewFuzzyQuery 模糊匹配
			elastic.NewMatchQuery("title", key),
		)
	}

	if limit == 0 {
		limit = 10
	}
	if from == 0 {
		from = 1
	}

	res, err := client.Search(DemoModel{}.Index()).
		Query(boolSearch).From((from - 1) * limit).
		Size(limit).Do(context.Background())
	if err != nil {
		logrus.Error(err.Error())
		return
	}
	// 搜索的结果数
	count = int(res.Hits.TotalHits.Value)
	for _, hit := range res.Hits.Hits {
		var demo DemoModel
		data, err := hit.Source.MarshalJSON()
		if err != nil {
			logrus.Error(err.Error())
			continue
		}
		err = json.Unmarshal(data, &demo)
		if err != nil {
			logrus.Error(err.Error())
			return
		}
		demo.ID = hit.Id
		demoList = append(demoList, demo)
	}
	return demoList, count
}

// FindSourceList 列表查询指定字段
func FindSourceList(key string, page, limit int) {
	// 创建一个新的布尔查询
	boolSearch := elastic.NewBoolQuery()
	from := page
	if key != "" {
		// Must方法表示这个匹配查询是必需的，也就是说只有当这个匹配查询返回结果时，布尔查询才会返回结果。
		boolSearch.Must(
			// NewMatchQuery 必须完全匹配 NewFuzzyQuery 模糊匹配
			elastic.NewMatchQuery("title", key),
		)
	}

	if limit == 0 {
		limit = 10
	}
	if from == 0 {
		from = 1
	}

	res, err := client.Search(DemoModel{}.Index()).
		Source(`{"_source": ["title"]}`).
		Query(boolSearch).
		From((from - 1) * limit).
		Size(limit).
		Do(context.Background())
	if err != nil {
		logrus.Error(err.Error())
		return
	}
	// 搜索的结果数
	count := int(res.Hits.TotalHits.Value)
	demoList := []DemoModel{}
	for _, hit := range res.Hits.Hits {
		var demo DemoModel
		data, err := hit.Source.MarshalJSON()
		if err != nil {
			logrus.Error(err.Error())
			continue
		}
		err = json.Unmarshal(data, &demo)
		if err != nil {
			logrus.Error(err.Error())
			continue
		}
		demo.ID = hit.Id
		demoList = append(demoList, demo)
	}
	fmt.Println(demoList, count)
}

// Update 修改指定字段更新
func Update(id string, data *DemoModel) error {
	_, err := client.Update().Index(DemoModel{}.Index()).
		Id(id).
		Doc(map[string]string{
			"title": data.Title,
		}).
		Do(context.Background())
	if err != nil {
		logrus.Error(err.Error())
		return err
	}
	logrus.Error("修改成功")
	return nil
}

// Delete 批量删除
func Delete(idList []string) (count int, err error) {
	bulkService := client.Bulk().Index(DemoModel{}.Index()).Refresh("true")
	for _, id := range idList {
		req := elastic.NewBulkDeleteRequest().Id(id)
		bulkService.Add(req)
	}
	res, err := bulkService.Do(context.Background())
	return len(res.Succeeded()), err
}

func main() {
	//DemoModel{}.CreateIndex()
	//DemoModel{}.DeleteIndex()
	//Create(&DemoModel{ // 添加
	//	Title:     "go教程",
	//	UserID:    2,
	//	CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
	//})
	//list, count := FindList("php", 1, 10) // 列表
	//fmt.Println(list, count)
	//FindSourceList("php教程", 1, 10)  // 索引失效
	//Update("utdC1YoBl5C1aTaYuOrJ", &DemoModel{Title: "golang零基础学习"}) // 修改
}
